from django.views import View
from django.shortcuts import render

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status, serializers, mixins, generics, viewsets, filters
from rest_framework.pagination import PageNumberPagination
from rest_framework.authentication import TokenAuthentication

from django_filters.rest_framework import DjangoFilterBackend

from .models import Goods, GoodsCategory, GoodsCategoryBrand
from .serializers import (GoodsSerializer01, GoodsSerializer02, CategorySerializer01,
                          CategorySerializer0301, ParentCategorySerializer0103,

                          )
from .filters import GoodsFilter01, GoodsFilter02


class GoodsListView01(APIView):
    """
    显示所有的商品列表，创建新的商品
    """

    def get(self, request, format=None):
        all_goods = Goods.objects.all()
        serializer = GoodsSerializer01(all_goods, many=True)  # 需要在应用下创建serializers.py文件写序列化类
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = GoodsSerializer01(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class GoodsListView02(generics.ListAPIView):
    """
    显示所有的商品列表
    基类提供核心功能，mixin类提供.list()和.create()操作。
    然后显式地将get和post方法绑定到适当的操作。到目前为止已经足够简单了。
    使用mixin类，重写了视图，比以前使用的代码稍微少一些，但是可以更进一步。
    REST框架提供了一组已经混合在一起的通用视图，可以使用这些视图来进一步简化GoodsListView模块。
    """
    queryset = Goods.objects.all()  # 可以取一定的数量
    serializer_class = GoodsSerializer02


class GoodsPagination01(PageNumberPagination):
    page_size = 3  # 默认每一页个数
    page_size_query_param = 'page_size'
    page_query_param = 'p'  # 参数?p=xx
    max_page_size = 36  # 最大指定每页个数


class GoodsPagination02(PageNumberPagination):
    page_size = 12  # 每一页个数，由于前段
    page_size_query_param = 'page_size'
    page_query_param = 'page'  # 参数?p=xx，将其修改为page，适应前端，也方便识别
    max_page_size = 36  # 最大指定每页个数


class GoodsListView03(generics.ListAPIView):
    """
    显示所有的商品列表
    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer02
    pagination_class = GoodsPagination01


class GoodsListViewSet01(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    显示商品列表
    ViewSets & Routers显示商品列表
    ViewSet类几乎与视图类相同，只是它们提供了诸如read或update之类的操作，而不是诸如get或put之类的方法处理程序。
    ViewSet类只在最后时刻绑定到一组方法处理程序，当它被实例化为一组视图时，通常通过使用一个Router类来处理为您定义URL conf的复杂性。

    """
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer02
    pagination_class = GoodsPagination01


class GoodsListViewSet02(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet)
    继承的viewsets.GenericViewSet（GenericViewSet(ViewSetMixin, generics.GenericAPIView)）
    继承的GenericAPIView(views.APIView)提供了一个get_queryset()方法，可以通过这个方法，进行过滤
    """
    queryset = Goods.objects.all()  # 使用get_queryset函数，依赖queryset的值
    serializer_class = GoodsSerializer02
    pagination_class = GoodsPagination01

    def get_queryset(self):
        return Goods.objects.filter(shop_price__gt=120)


class GoodsListViewSet03(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    显示商品列表
    """
    queryset = Goods.objects.all()  # 使用get_queryset函数，依赖queryset的值
    serializer_class = GoodsSerializer02
    pagination_class = GoodsPagination01

    def get_queryset(self):
        queryset = self.queryset
        # 传递价格区间的参数
        price_min = self.request.query_params.get('price_min')
        if price_min:
            queryset = queryset.filter(shop_price__gte=price_min)
        return queryset


class GoodsListViewSet04(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    显示商品列表
    """
    queryset = Goods.objects.all()  # 使用get_queryset函数，依赖queryset的值
    serializer_class = GoodsSerializer02
    pagination_class = GoodsPagination01
    filter_backends = (DjangoFilterBackend,)  # 将过滤器后端添加到单个视图或视图集
    filterset_fields = ('name', 'goods_desc',)


class GoodsListViewSet05(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    django-filter的使用
    显示商品列表
    """
    queryset = Goods.objects.all()  # 使用get_queryset函数，依赖queryset的值
    serializer_class = GoodsSerializer02
    pagination_class = GoodsPagination01
    filter_backends = (DjangoFilterBackend,)  # 将过滤器后端添加到单个视图或视图集
    filterset_class = GoodsFilter01


class GoodsListViewSet06(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    使用SearchFilter
    参考： https://www.django-rest-framework.org/api-guide/filtering/#searchfilter

    搜索最适合模糊匹配
    SearchFilter类支持简单的基于查询参数的搜索，并且基于Django管理员的搜索功能。
    search_fields属性应该是模型中文本类型字段的名称列表，例如CharField或TextField。
    默认情况下，搜索将使用不区分大小写的部分匹配。搜索参数可以包含多个搜索项，这些搜索项应该用空格和/或逗号分隔。如果使用多个搜索项，则仅当所提供的所有项都匹配时，才会在列表中返回对象。

    搜索行为可能受到search_fields前置各种字符的限制。

    ^：以搜索的文本开始。
    =：精确匹配。
    @：全文搜索。(目前只支持Django的MySQL后端)。
    $：正则表达式搜索。
    显示商品列表
    """
    queryset = Goods.objects.all()  # 使用get_queryset函数，依赖queryset的值
    serializer_class = GoodsSerializer02
    pagination_class = GoodsPagination01
    filter_backends = (DjangoFilterBackend, filters.SearchFilter,)  # 将过滤器后端添加到单个视图或视图集
    filterset_class = GoodsFilter01
    search_fields = ('name', 'goods_desc', 'category__name')  # 最后表示搜索外键分类名称


class GoodsListViewSet07(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    使用OrderingFilter
    参考： https://www.django-rest-framework.org/api-guide/filtering/#orderingfilter

    OrderingFilter类支持简单的查询参数控制的结果排序。

    默认情况下，查询参数名为ordered，但是可以通过ORDERING_PARAM设置覆盖该参数。
    显示商品列表，分页、过滤、搜索、排序
    """
    queryset = Goods.objects.all()  # 使用get_queryset函数，依赖queryset的值
    serializer_class = GoodsSerializer02
    pagination_class = GoodsPagination02
    filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter,)  # 将过滤器后端添加到单个视图或视图集
    filterset_class = GoodsFilter02
    search_fields = ('name', 'goods_desc', 'category__name')  # 搜索字段
    ordering_fields = ('click_num', 'sold_num', 'shop_price')  # 排序

    authentication_classes = (TokenAuthentication,)  # 只在本视图中验证Token


class CategoryViewSet01(mixins.ListModelMixin, viewsets.GenericViewSet):
    # 注释很有用，在drf文档中，可以自动提取出来
    """
    list:
        商品分类列表
    """
    queryset = GoodsCategory.objects.all()  # 取出所有分类，没必要分页，因为分类数据量不大
    serializer_class = CategorySerializer01  # 使用商品类别序列化类，写商品的分类外键已有，直接调用


class CategoryViewSet02(mixins.ListModelMixin, viewsets.GenericViewSet):
    # 注释很有用，在drf文档中
    """
    list:
        商品分类列表
    """
    # queryset = GoodsCategory.objects.all()  # 取出所有分类，没必要分页，因为分类数据量不大
    queryset = GoodsCategory.objects.filter(category_type=1)  # 只获取一级分类数据
    serializer_class = CategorySerializer0301  # 使用商品类别序列化类，写商品的分类外键已有，直接调用


class CategoryViewSet03(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    # 注释很有用，在drf文档中
    """
    这个继承主要是获取某个对象的详情，且这只需要这样写即可。

    Restful Api规范中要获取某个对象的详情，只需要在其后面添加某个对象的ID即可。

    DRF已经做好了，不需要手动配置获取详情的URL，只需要在ViewSe中继承mixins.RetrieveModelMixin即可，其他什么都不需要

    访问 http://127.0.0.1:8000/categories/ 可以显示分类列表，加上一级分类ID可以获得某个具体的分类，比如： http://127.0.0.1:8000/categories/121/?format=json ，这个一级分类详情数据主要是显示在前端左侧的分类列表。
    list:
        商品分类列表
    """
    # queryset = GoodsCategory.objects.all()  # 取出所有分类，没必要分页，因为分类数据量不大
    queryset = GoodsCategory.objects.filter(category_type=1)  # 只获取一级分类数据
    serializer_class = CategorySerializer0301  # 使用商品类别序列化类，写商品的分类外键已有，直接调用


class ParentCategoryViewSet01(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    """
    list:
        根据子类别查询父类别
    """
    queryset = GoodsCategory.objects.all()
    serializer_class = ParentCategorySerializer0103


class MyTestView01(View):
    def get(self, request):
        return render(request, 'testform.html', locals())
